/**
 * Class to parse Delta bank credit page and getting credits info
 * User: kaiser
 * Date: 6/4/13
 * Time: 10:46 PM
 */
package com.google.code.bankagregator.adapter.bank.delta.parser.credit;

import com.google.code.bankagregator.adapter.exception.AdapterException;
import com.google.code.bankagregator.adapter.exception.AdapterRecognizeDataException;
import com.google.code.bankagregator.common.DetectCurrency;
import com.google.code.bankagregator.common.SiteConnect;
import com.google.code.bankagregator.common.reader.CreditReader;
import com.google.code.bankagregator.entities.*;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CreditGotivkaParser implements CreditReader {

    /**
     * Column number with "new cache" credits details
     */
    public final int NEW_CACHE_INDEX = 1;
    /**
     * Column number with "cache 2012" credits details
     */
    public final int CACHE_2012 = 2;
    /**
     * Row with credits name details
     */
    public final int NAME_ROW = 0;
    /**
     * Row with credits limit details
     */
    public final int LIMIT_CURRENCY_ROW = 1;
    /**
     * Row with credits rate details
     */
    public final int RATE_ROW = 4;
    /**
     * Row with credits period details
     */
    public final int PERIOD_ROW = 15;
    /**
     * index of first element in list
     */
    public final int FIRST_ELEMENT = 0;
    /**
     * URL with credits details
     */
    public String url = null;
    /**
     * List of parsed credits
     */
    List<Credit> creditList = new ArrayList<>();

    private Bank bank;

    public CreditGotivkaParser(String url) {
        this.url = url;
        bank = new Bank();
        bank.setName("ПАО \"Дельта Банк\"");
        bank.setUrl("http://gotivochka.com.ua/");
    }

    /**
     * Parser "New cache" credit details
     *
     * @param trs table rows elements
     */
    private void parseNewCacheOffer(Elements trs) throws AdapterException {
        parseTableColumn(trs, NEW_CACHE_INDEX);
    }

    /**
     * Parser "Cache 2012" credit details
     *
     * @param trs table rows elements
     */
    private void parse2012Cache(Elements trs) throws AdapterException {
        parseTableColumn(trs, CACHE_2012);
    }

    /**
     * Table row parser and getting info from some column
     *
     * @param trs    table rows elements
     * @param column number of column with some credit details
     */
    private void parseTableColumn(Elements trs, int column) throws AdapterException {
        int size = trs.size();
        Credit credit = new Credit();
        credit.setType(CreditType.CONSUMER);
        for (int trLine = 0; trLine < size; trLine++) {
            Element tr = trs.get(trLine);
            Elements tds = tr.select("td");
            if (!tds.isEmpty()) {
                if (tds.size() > column) {
                    Element td = tds.get(column);
                    switch (trLine) {
                        case NAME_ROW:
                            credit.setName(parseName(td));
                            break;
                        case LIMIT_CURRENCY_ROW:
                            credit.setMaxAmount(parseAmount(td));
                            credit.setCurrency(parseCurrency(td));
                            break;
                        case RATE_ROW:
                            credit.setCreditRate(parseRate(td));
                            break;
                        case PERIOD_ROW:
                            credit.setTerm(parsePeriod(td));
                            break;
                    }
                }
            }
        }
        credit.setPrepayment(0.0);
        credit.setBank(bank);
        credit.setUrl(url);
        credit.setState(State.ACTIVE);
        creditList.add(credit);
    }

    /**
     * Parse name from TR Table Element
     *
     * @param td Element of table
     * @return Credit name
     */
    private String parseName(Element td) {
        Elements h3 = td.select("h3");
        if (h3.isEmpty()) {
            return "";
        }
        String name = h3.get(FIRST_ELEMENT).text();
        return name.replace("\u00ab", "").replace("\u00bb", "");
    }

    /**
     * Parse amount from TR Table Element
     *
     * @param td Element of table
     * @return Credit amount
     */
    private int parseAmount(Element td) {
        Elements spans = td.select("span");
        if (spans.isEmpty()) {
            return 0;
        }
        Element span = spans.get(FIRST_ELEMENT);
        Pattern pattern = Pattern.compile("\\d+");
        String amountText = span.text();
        amountText = amountText.replaceAll("\u00a0", ""); // remove &nbsp;
        amountText = amountText.replaceAll("\\s*", "");  // remove spaces

        Matcher amount = pattern.matcher(amountText);
        if (amount.find()) {
            return Integer.parseInt(amount.group());
        } else {
            return 0;
        }
    }

    /**
     * Parse currency from TR Table Element
     *
     * @param td Element of table
     * @return Credit currency
     */
    private Currency parseCurrency(Element td) {
        DetectCurrency recodeDetectCurrency = new DetectCurrency();
        String curr = recodeDetectCurrency.getCurrencyAbbreviation(td.text());
        return Currency.valueOf(curr);
    }

    /**
     * Parse rate from TR Table Element
     *
     * @param td Element of table
     * @return Credit rate
     */
    private double parseRate(Element td) throws AdapterException {
        Elements spans = td.select("span");
        if (!spans.isEmpty()) {
            Element span = spans.get(FIRST_ELEMENT);
            NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
            try {
                Number number = format.parse(span.text().replaceAll("%", ""));
                return number.doubleValue();
            } catch (ParseException e) {
                throw new AdapterRecognizeDataException("Delta bank parsing error. #003");
            }
        }
        return 0;
    }

    /**
     * Parse period from TR Table Element
     *
     * @param td Element of table
     * @return Credit period
     */
    private int parsePeriod(Element td) {
        /**
         * @todo add period parser
         */
        return 50 * 31;
    }

    /**
     * Getting certain table prom page
     *
     * @return table Element with credits data
     */
    private Element getTableWithContent(Document doc) {
        Elements tables = doc.select("table table");
        if (tables.isEmpty()) {
            return null;
        } else {
            return tables.get(FIRST_ELEMENT);
        }
    }

    @Override
    public List<Credit> getCredits() throws AdapterException {
        Document doc = new SiteConnect(this.url).getPage();
        Element table = getTableWithContent(doc);
        if (table == null) {
            throw new AdapterRecognizeDataException("Delta bank parsing error. #001");
        } else {
            Elements trs = table.select("tr");
            if (trs.isEmpty()) {
                throw new AdapterRecognizeDataException("Delta bank parsing error. #002");
            } else {
                parseNewCacheOffer(trs);
                parse2012Cache(trs);
            }
        }
        return creditList;
    }
}